using System;
using System.Text;

namespace ICSharpCode.TextEditor.Document
{
    public class DefaultFormattingStrategy : IFormattingStrategy
    {
        private static readonly char[] whitespaceChars = new char[2] { ' ', '\t' };

        protected string GetIndentation(TextArea textArea, int lineNumber)
        {
            if (lineNumber < 0 || lineNumber > textArea.Document.TotalNumberOfLines)
            {
                throw new ArgumentOutOfRangeException("lineNumber");
            }
            string lineAsString = TextUtilities.GetLineAsString(textArea.Document, lineNumber);
            StringBuilder stringBuilder = new StringBuilder();
            string text = lineAsString;
            foreach (char c in text)
            {
                if (char.IsWhiteSpace(c))
                {
                    stringBuilder.Append(c);
                    continue;
                }
                break;
            }
            return stringBuilder.ToString();
        }

        protected virtual int AutoIndentLine(TextArea textArea, int lineNumber)
        {
            string text = ((lineNumber != 0) ? GetIndentation(textArea, checked(lineNumber - 1)) : "");
            if (text.Length > 0)
            {
                string newLineText = text + TextUtilities.GetLineAsString(textArea.Document, lineNumber).Trim();
                LineSegment lineSegment = textArea.Document.GetLineSegment(lineNumber);
                SmartReplaceLine(textArea.Document, lineSegment, newLineText);
            }
            return text.Length;
        }

        public static void SmartReplaceLine(IDocument document, LineSegment line, string newLineText)
        {
            if (document == null)
            {
                throw new ArgumentNullException("document");
            }
            if (line == null)
            {
                throw new ArgumentNullException("line");
            }
            if (newLineText == null)
            {
                throw new ArgumentNullException("newLineText");
            }
            string text = newLineText.Trim(whitespaceChars);
            string text2 = document.GetText(line);
            if (text2 == newLineText)
            {
                return;
            }
            int num = text2.IndexOf(text);
            checked
            {
                if (text.Length > 0 && num >= 0)
                {
                    document.UndoStack.StartUndoGroup();
                    try
                    {
                        int i;
                        for (i = 0; i < newLineText.Length; i++)
                        {
                            char c = newLineText[i];
                            if (c != ' ' && c != '\t')
                            {
                                break;
                            }
                        }
                        int num2 = newLineText.Length - text.Length - i;
                        int offset = line.Offset;
                        document.Replace(offset + num + text.Length, line.Length - num - text.Length, newLineText.Substring(newLineText.Length - num2));
                        document.Replace(offset, num, newLineText.Substring(0, i));
                        return;
                    }
                    finally
                    {
                        document.UndoStack.EndUndoGroup();
                    }
                }
                document.Replace(line.Offset, line.Length, newLineText);
            }
        }

        protected virtual int SmartIndentLine(TextArea textArea, int line)
        {
            return AutoIndentLine(textArea, line);
        }

        public virtual void FormatLine(TextArea textArea, int line, int cursorOffset, char ch)
        {
            if (ch == '\n')
            {
                textArea.Caret.Column = IndentLine(textArea, line);
            }
        }

        public int IndentLine(TextArea textArea, int line)
        {
            textArea.Document.UndoStack.StartUndoGroup();
            int result;
            switch (textArea.Document.TextEditorProperties.IndentStyle)
            {
                case IndentStyle.None:
                    result = 0;
                    break;
                case IndentStyle.Auto:
                    result = AutoIndentLine(textArea, line);
                    break;
                case IndentStyle.Smart:
                    result = SmartIndentLine(textArea, line);
                    break;
                default:
                    throw new NotSupportedException("Unsupported value for IndentStyle: " + textArea.Document.TextEditorProperties.IndentStyle);
            }
            textArea.Document.UndoStack.EndUndoGroup();
            return result;
        }

        public virtual void IndentLines(TextArea textArea, int begin, int end)
        {
            textArea.Document.UndoStack.StartUndoGroup();
            for (int i = begin; i <= end; i = checked(i + 1))
            {
                IndentLine(textArea, i);
            }
            textArea.Document.UndoStack.EndUndoGroup();
        }

        public virtual int SearchBracketBackward(IDocument document, int offset, char openBracket, char closingBracket)
        {
            int num = -1;
            checked
            {
                for (int num2 = offset; num2 >= 0; num2--)
                {
                    char charAt = document.GetCharAt(num2);
                    if (charAt == openBracket)
                    {
                        num++;
                        if (num == 0)
                        {
                            return num2;
                        }
                    }
                    else if (charAt == closingBracket)
                    {
                        num--;
                    }
                }
                return -1;
            }
        }

        public virtual int SearchBracketForward(IDocument document, int offset, char openBracket, char closingBracket)
        {
            int num = 1;
            checked
            {
                for (int i = offset; i < document.TextLength; i++)
                {
                    char charAt = document.GetCharAt(i);
                    if (charAt == openBracket)
                    {
                        num++;
                    }
                    else if (charAt == closingBracket)
                    {
                        num--;
                        if (num == 0)
                        {
                            return i;
                        }
                    }
                }
                return -1;
            }
        }
    }
}
